package homework;


// 导入JDBC相关类，用于数据库连接和操作
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;  // 导入Scanner类，用于接收用户输入

// 定义CRUD操作的主类，类名必须与文件名一致
public class CRUDOperations {
    // 数据库连接常量，使用private static final修饰表示不可修改的类级常量
    // 数据库URL，包含数据库地址、端口、数据库名和连接参数
    private static final String URL = "jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root";  // 数据库用户名
    private static final String PASSWORD = "root";  // 数据库密码

    // 数据库表和字段名常量，方便后续修改维护
    private static final String TABLE_NAME = "users";  // 表名
    private static final String ID_FIELD = "id";  // ID字段名
    private static final String NAME_FIELD = "name";  // 姓名字段名
    private static final String EMAIL_FIELD = "email";  // 邮箱字段名

    // 主方法，程序入口点
    public static void main(String[] args) {
        Connection conn = null;  // 声明数据库连接对象，初始化为null
        Scanner scanner = new Scanner(System.in);  // 创建Scanner对象，用于读取用户输入

        try {
            // 加载MySQL JDBC驱动，反射机制加载类
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 建立数据库连接，通过DriverManager获取连接对象
            conn = DriverManager.getConnection(URL, USER, PASSWORD);
            System.out.println("数据库连接成功！");  // 连接成功提示

            // 程序启动时检查并创建表（如果不存在）
            if (!isTableExists(conn, TABLE_NAME)) {
                System.out.println("检测到表不存在，正在创建表...");
                createTable(conn);
            } else {
                System.out.println("表已存在，可以开始操作数据");
            }

            int choice;  // 声明用户选择变量
            // 循环显示菜单，直到用户选择退出(选项6)
            do {
                printMenu();  // 调用打印菜单方法
                System.out.print("请输入你的选择: ");  // 提示用户输入
                choice = scanner.nextInt();  // 获取用户选择的整数
                scanner.nextLine();  // 消耗输入缓冲区中的换行符，避免后续读取问题

                // 根据用户选择执行相应操作
                switch (choice) {
                    case 1:
                        createTable(conn);  // 调用创建表方法
                        break;
                    case 2:
                        insertData(conn, scanner);  // 调用插入数据方法
                        break;
                    case 3:
                        queryData(conn);  // 调用查询数据方法
                        break;
                    case 4:
                        updateData(conn, scanner);  // 调用更新数据方法
                        break;
                    case 5:
                        deleteData(conn, scanner);  // 调用删除数据方法
                        break;
                    case 6:
                        System.out.println("感谢使用，程序退出！");  // 退出提示
                        break;
                    default:
                        System.out.println("无效的选择，请重新输入！");  // 无效选择提示
                }

                // 如果不是退出选项，暂停让用户看清结果
                if (choice!= 6) {
                    System.out.println("\n按回车键继续...");
                    scanner.nextLine();  // 等待用户按回车
                }
            } while (choice!= 6);  // 当选择不是6时继续循环

        } catch (Exception e) {
            e.printStackTrace();  // 打印异常信息
        } finally {
            // 关闭数据库连接和扫描器，确保资源释放
            try {
                // 检查连接是否存在且未关闭，如果是则关闭
                if (conn!= null &&!conn.isClosed()) {
                    conn.close();
                    System.out.println("数据库连接已关闭");
                }
            } catch (Exception e) {
                e.printStackTrace();  // 处理关闭连接时的异常
            }
            // 关闭扫描器
            if (scanner!= null) {
                scanner.close();
            }
        }
    }

    // 打印操作菜单的方法，增加了创建表选项
    private static void printMenu() {
        System.out.println("\n===== 数据操作菜单 =====");
        System.out.println("1. 创建表");
        System.out.println("2. 插入数据");
        System.out.println("3. 查询所有数据");
        System.out.println("4. 更新数据");
        System.out.println("5. 删除数据");
        System.out.println("6. 退出程序");
        System.out.println("=======================");
    }

    // 创建表的方法
    private static void createTable(Connection conn) {
        try {
            // 检查表是否已存在
            if (isTableExists(conn, TABLE_NAME)) {
                System.out.println("表 " + TABLE_NAME + " 已存在，无需重复创建！");
                return;
            }

            // SQL创建表语句，id为主键并自增
            String createTableSQL = "CREATE TABLE " + TABLE_NAME + " (" +
                    ID_FIELD + " INT AUTO_INCREMENT PRIMARY KEY, " +
                    NAME_FIELD + " VARCHAR(50) NOT NULL, " +
                    EMAIL_FIELD + " VARCHAR(100) UNIQUE NOT NULL)";

            // 创建Statement对象执行SQL
            Statement stmt = conn.createStatement();
            stmt.execute(createTableSQL);
            System.out.println("表 " + TABLE_NAME + " 创建成功！");

            stmt.close();  // 关闭资源
        } catch (Exception e) {
            System.out.println("创建表失败：" + e.getMessage());
            e.printStackTrace();
        }
    }

    // 检查表是否存在的辅助方法
    private static boolean isTableExists(Connection conn, String tableName) {
        try {
            // 获取数据库元数据
            DatabaseMetaData metaData = conn.getMetaData();
            // 查询指定表是否存在
            ResultSet rs = metaData.getTables(null, null, tableName, new String[]{"TABLE"});
            // 如果结果集有记录，说明表存在
            boolean exists = rs.next();

            rs.close();  // 关闭结果集
            return exists;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    // 插入数据的方法，参数为数据库连接和扫描器对象
    private static void insertData(Connection conn, Scanner scanner) {
        try {
            // SQL插入语句，使用占位符?防止SQL注入
            String sql = "INSERT INTO " + TABLE_NAME + " (" + NAME_FIELD + ", " + EMAIL_FIELD + ") VALUES (?,?)";
            // 创建PreparedStatement对象，用于执行带参数的SQL
            PreparedStatement pstmt = conn.prepareStatement(sql);

            // 提示用户输入数据
            System.out.print("请输入" + NAME_FIELD + ": ");
            String name = scanner.nextLine();  // 获取用户输入的姓名
            System.out.print("请输入" + EMAIL_FIELD + ": ");
            String email = scanner.nextLine();  // 获取用户输入的邮箱

            // 为SQL语句中的占位符设置值
            pstmt.setString(1, name);  // 第一个占位符设置为姓名
            pstmt.setString(2, email);  // 第二个占位符设置为邮箱

            // 执行更新操作，返回受影响的行数
            int rowsAffected = pstmt.executeUpdate();
            // 根据受影响行数判断操作是否成功
            if (rowsAffected > 0) {
                System.out.println("数据插入成功！");
            } else {
                System.out.println("数据插入失败！");
            }

            pstmt.close();  // 关闭PreparedStatement对象，释放资源
        } catch (Exception e) {
            e.printStackTrace();  // 处理异常
        }
    }

    // 查询所有数据的方法
    private static void queryData(Connection conn) {
        try {
            // SQL查询语句，查询表中所有数据
            String sql = "SELECT * FROM " + TABLE_NAME;
            // 创建Statement对象，用于执行SQL语句
            Statement stmt = conn.createStatement();
            // 执行查询，返回结果集ResultSet
            ResultSet rs = stmt.executeQuery(sql);

            boolean hasData = false;  // 标记是否有数据
            System.out.println("\n----- 所有数据 -----");
            // 遍历结果集，next()方法移动到下一行，有数据返回true
            while (rs.next()) {
                hasData = true;  // 标记有数据
                // 从结果集中获取数据，参数可以是字段名或索引
                int id = rs.getInt(ID_FIELD);  // 获取ID
                String name = rs.getString(NAME_FIELD);  // 获取姓名
                String email = rs.getString(EMAIL_FIELD);  // 获取邮箱
                // 格式化输出数据
                System.out.printf("%d. %s - %s%n", id, name, email);
            }

            // 如果没有数据，提示用户
            if (!hasData) {
                System.out.println("没有数据记录！");
            }

            // 关闭结果集和Statement对象
            rs.close();
            stmt.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 更新数据的方法
    private static void updateData(Connection conn, Scanner scanner) {
        try {
            System.out.print("请输入要更新的数据ID: ");
            int id = scanner.nextInt();  // 获取要更新的ID
            scanner.nextLine();  // 消耗换行符

            // 先检查ID是否存在，不存在则提示并返回
            if (!isIdExists(conn, id)) {
                System.out.println("ID不存在，无法更新！");
                return;
            }

            // SQL更新语句，使用占位符
            String sql = "UPDATE " + TABLE_NAME + " SET " + NAME_FIELD + " =?, " + EMAIL_FIELD + " =? WHERE " + ID_FIELD + " =?";
            PreparedStatement pstmt = conn.prepareStatement(sql);

            // 获取用户输入的新数据
            System.out.print("请输入新的" + NAME_FIELD + ": ");
            String name = scanner.nextLine();
            System.out.print("请输入新的" + EMAIL_FIELD + ": ");
            String email = scanner.nextLine();

            // 设置参数，前两个是新值，最后一个是WHERE条件的ID
            pstmt.setString(1, name);
            pstmt.setString(2, email);
            pstmt.setInt(3, id);

            // 执行更新，获取受影响行数
            int rowsAffected = pstmt.executeUpdate();
            if (rowsAffected > 0) {
                System.out.println("数据更新成功！");
            } else {
                System.out.println("数据更新失败！");
            }

            pstmt.close();  // 关闭资源
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 删除数据的方法
    private static void deleteData(Connection conn, Scanner scanner) {
        try {
            System.out.print("请输入要删除的数据ID: ");
            int id = scanner.nextInt();  // 获取要删除的ID
            scanner.nextLine();  // 消耗换行符

            // 检查ID是否存在
            if (!isIdExists(conn, id)) {
                System.out.println("ID不存在，无法删除！");
                return;
            }

            // 询问用户是否确认删除，防止误操作
            System.out.print("确定要删除ID为" + id + "的数据吗？(y/n): ");
            String confirm = scanner.nextLine();
            // 如果用户输入不是y或Y，取消删除
            if (!confirm.equalsIgnoreCase("y")) {
                System.out.println("已取消删除操作！");
                return;
            }

            // SQL删除语句
            String sql = "DELETE FROM " + TABLE_NAME + " WHERE " + ID_FIELD + " =?";
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, id);  // 设置要删除的ID

            // 执行删除
            int rowsAffected = pstmt.executeUpdate();
            if (rowsAffected > 0) {
                System.out.println("数据删除成功！");
            } else {
                System.out.println("数据删除失败！");
            }

            pstmt.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 检查ID是否存在的辅助方法，返回布尔值
    private static boolean isIdExists(Connection conn, int id) {
        try {
            // 查询是否存在该ID的记录，只需要返回1即可
            String sql = "SELECT 1 FROM " + TABLE_NAME + " WHERE " + ID_FIELD + " =?";
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, id);  // 设置要检查的ID

            ResultSet rs = pstmt.executeQuery();
            // 如果结果集有下一行，说明存在该ID
            boolean exists = rs.next();

            // 关闭资源
            rs.close();
            pstmt.close();
            return exists;  // 返回是否存在
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}

